package logic

import (
	"callsips/internal/config"
	"callsips/internal/model/sips/srecord"
	"callsips/internal/model/sips/srecorderr"
	"callsips/internal/svc"
	"callsips/internal/types"
	"callsips/internal/utils"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
	"github.com/hibiken/asynq"
	"github.com/zeromicro/go-zero/core/logx"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

type FsrecordLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// 话单处理
func (l *FsrecordLogic) Record(req *types.FsRecordReq) (err error) {
	if len(req.Callflow) == 0 {
		return nil
	}

	//reqs, _ := json.Marshal(req.Variables)
	//logx.Info(string(reqs))

	//查询是否是正确的话单
	var sipFromUser string = req.Callflow[0].CallerProfile["caller_id_number"].(string)
	if _, err = l.svcCtx.AccountSips.FindOneByUsername(l.ctx, sipFromUser); err != nil {
		var errRecord = l.paserVariablesErr(req.Variables, req.Callflow[0])
		errRecord.State = req.ChannelData["state"]
		stateNumber, _ := strconv.Atoi(req.ChannelData["state_number"])
		errRecord.StateNumber = int64(stateNumber)
		if _, err = l.svcCtx.SipRecordErr.Insert(l.ctx, errRecord); err != nil {
			logx.Infof("错误话单信息为:%s", err.Error())
			return err
		}

		return nil
	}

	var records = l.paserVariables(req.Variables, req.Callflow[0])
	records.State = req.ChannelData["state"]
	stateNumber, _ := strconv.Atoi(req.ChannelData["state_number"])
	records.StateNumber = int64(stateNumber)

	if len(req.Callflow) == 0 {
		return errors.New("话单时间错误")
	}

	var calltime = l.paserCallTime(req.Callflow[0].Times)

	records.CreatedTime = calltime.CreatedTime               // 通话创建时间
	records.ProfileCreatedTime = calltime.ProfileCreatedTime // SIP Profile生效时间
	records.ProgressTime = calltime.ProgressTime             // SIP协议层时间
	records.ProgressMediaTime = calltime.ProgressMediaTime   // 媒体通道建立时间
	records.AnsweredTime = calltime.AnsweredTime             // 被叫应答时刻（接通时间）
	records.BridgedTime = calltime.BridgedTime               // 双路通话桥接完成时间
	records.LastHoldTime = calltime.LastHoldTime             // 最后一次开启保持的时间
	records.HoldAccumTime = calltime.HoldAccumTime           // 累计保持时长
	records.HangupTime = calltime.HangupTime                 // 通话结束时间
	records.ResurrectTime = calltime.ResurrectTime           // 通话从保持状态恢复的时间
	records.TransferTime = calltime.TransferTime             // 通话被转移的时间

	if _, err = l.svcCtx.SipRecord.Insert(l.ctx, records); err != nil {
		logx.Infof("同步通话记录失败：%s", err.Error())
		return err
	}

	//异步通知
	if records.Accountcode == "" {
		logx.Info("同步通话记录失败：Accountcode 为空")
		return nil
	}

	var customerId = req.Variables["customer_id"]
	var accountId = req.Variables["account_id"]
	var taocanId = req.Variables["taocan_id"]
	var kindId = req.Variables["kind"]
	var trackId = req.Variables["track_id"]
	var trackTaskId = req.Variables["task_track_id"]
	logx.Infof("同步通话记录失败:customerId=%s,accountId=%s,taocanId=%s,kindId=%s,trackId=%s,trackTaskId=%s", customerId, accountId, taocanId, kindId, trackId, trackTaskId)
	if customerId == "" || accountId == "" || taocanId == "" || kindId == "" {
		return nil
	}

	customerIdInt, _ := strconv.Atoi(customerId)
	accountIdInt, _ := strconv.Atoi(accountId)
	taocanIdInt, _ := strconv.Atoi(taocanId)
	kindIdInt, _ := strconv.Atoi(kindId)
	trackIdInt, _ := strconv.Atoi(trackId)
	trackTaskIdInt, _ := strconv.Atoi(trackTaskId)

	var result map[string]any = map[string]any{
		"record_id":     strings.ReplaceAll(records.Uuid, "-", ""),
		"customer_id":   customerIdInt,
		"account_id":    accountIdInt,
		"taocan_id":     taocanIdInt,
		"kind_id":       kindIdInt,
		"track_id":      trackIdInt,
		"task_track_id": trackTaskIdInt,
		"send_phone":    records.CallerIdNumber,
		"accept_phone":  records.SipToUser,
		"second":        records.Billsec,
		"duration":      records.Duration,
		"hang_up":       utils.HangHpStatus(req.Variables),
		"created_time":  records.CreatedTime,
		"answered_time": records.AnsweredTime,
		"hangup_time":   records.HangupTime,
		"products_id":   3,
		"record_file":   records.RecordFile,
	}

	payload, _ := json.Marshal(result)
	if _, err = l.svcCtx.AsynqClient.Enqueue(asynq.NewTask("customer:record:yunhu", payload, asynq.MaxRetry(3))); err != nil {
		logx.Infof("处理座席状态队列:错误信息为：%s", err.Error())
		return err
	}

	if records.Billsec > 0 {
		//上传录音到阿里云oss
		go l.uploadRecordToOss(l.svcCtx.Config, records.RecordFile)
	}

	return nil
}

// 解析主叫信息
func (l *FsrecordLogic) paserVariables(variables map[string]string, callflow types.Callflow) *srecord.SipsSrecord {
	var record = &srecord.SipsSrecord{}
	record.Uuid = variables["uuid"]
	record.Direction = variables["direction"]
	record.SipFromUser = callflow.CallerProfile["caller_id_number"].(string)
	record.SipFromIp = callflow.CallerProfile["network_addr"].(string)
	record.SipViaProtocol = variables["sip_via_protocol"]
	record.CallerIdNumber = variables["effective_caller_id_number"]
	record.CallerIdName = variables["effective_caller_id_name"]
	record.SipToUser = callflow.CallerProfile["destination_number"].(string)
	record.SipToIp = variables["sip_to_host"]
	record.SipCallId = strings.ReplaceAll(variables["sip_call_id"], "-", "")
	record.Accountcode = variables["accountcode"]
	record.UserContext = variables["user_context"]
	record.Gateways = strings.ReplaceAll(variables["current_application_data"], "%40", "@")
	record.Records = variables["record_file_size"]
	duration, _ := strconv.Atoi(variables["duration"])
	record.Duration = int64(duration)
	waitsec, _ := strconv.Atoi(variables["waitsec"])
	record.Waitsec = int64(waitsec)
	billsec, _ := strconv.Atoi(variables["billsec"])
	record.Billsec = int64(billsec)
	answersec, _ := strconv.Atoi(variables["answersec"])
	record.Answersec = int64(answersec)

	sipUserAgent, _ := url.QueryUnescape(variables["sip_user_agent"])
	record.SipUserAgent = sipUserAgent

	record.HangupCause = variables["hangup_cause"]

	hangupCauseQ850, _ := strconv.Atoi(variables["hangup_cause_q850"])

	record.HangupCauseQ850 = int64(hangupCauseQ850)

	record.SipHangupDisposition = variables["sip_hangup_disposition"]
	record.BridgeHangupCause = variables["bridge_hangup_cause"]
	if billsec > 0 {
		record.RecordFile = fmt.Sprintf("%s.mp3", record.Uuid)
	}

	return record
}

// 错误的话单信息
func (l *FsrecordLogic) paserVariablesErr(variables map[string]string, callflow types.Callflow) *srecorderr.SipsSrecordErr {
	var record = &srecorderr.SipsSrecordErr{}
	record.Uuid = variables["uuid"]
	record.Direction = variables["direction"]
	record.SipFromUser = callflow.CallerProfile["caller_id_number"].(string)
	record.SipFromIp = callflow.CallerProfile["network_addr"].(string)
	record.SipViaProtocol = variables["sip_via_protocol"]
	record.CallerIdNumber = variables["effective_caller_id_number"]
	record.CallerIdName = variables["effective_caller_id_name"]
	record.SipToUser = callflow.CallerProfile["destination_number"].(string)
	record.SipToIp = variables["sip_to_host"]
	record.SipCallId = strings.ReplaceAll(variables["sip_call_id"], "-", "")
	record.Accountcode = variables["accountcode"]
	record.UserContext = variables["user_context"]
	record.Gateways = strings.ReplaceAll(variables["current_application_data"], "%40", "@")
	record.Records = variables["record_file_size"]
	duration, _ := strconv.Atoi(variables["duration"])
	record.Duration = int64(duration)
	waitsec, _ := strconv.Atoi(variables["waitsec"])
	record.Waitsec = int64(waitsec)
	billsec, _ := strconv.Atoi(variables["billsec"])
	record.Billsec = int64(billsec)
	answersec, _ := strconv.Atoi(variables["answersec"])
	record.Answersec = int64(answersec)

	sipUserAgent, _ := url.QueryUnescape(variables["sip_user_agent"])
	record.SipUserAgent = sipUserAgent

	record.HangupCause = variables["hangup_cause"]

	hangupCauseQ850, _ := strconv.Atoi(variables["hangup_cause_q850"])

	record.HangupCauseQ850 = int64(hangupCauseQ850)

	record.SipHangupDisposition = variables["sip_hangup_disposition"]
	record.BridgeHangupCause = variables["bridge_hangup_cause"]
	if billsec > 0 {
		record.RecordFile = fmt.Sprintf("%s.mp3", record.Uuid)
	}

	var calltime = l.paserCallTime(callflow.Times)

	record.CreatedTime = calltime.CreatedTime               // 通话创建时间
	record.ProfileCreatedTime = calltime.ProfileCreatedTime // SIP Profile生效时间
	record.ProgressTime = calltime.ProgressTime             // SIP协议层时间
	record.ProgressMediaTime = calltime.ProgressMediaTime   // 媒体通道建立时间
	record.AnsweredTime = calltime.AnsweredTime             // 被叫应答时刻（接通时间）
	record.BridgedTime = calltime.BridgedTime               // 双路通话桥接完成时间
	record.LastHoldTime = calltime.LastHoldTime             // 最后一次开启保持的时间
	record.HoldAccumTime = calltime.HoldAccumTime           // 累计保持时长
	record.HangupTime = calltime.HangupTime                 // 通话结束时间
	record.ResurrectTime = calltime.ResurrectTime           // 通话从保持状态恢复的时间
	record.TransferTime = calltime.TransferTime             // 通话被转移的时间

	return record
}

// 解析时间
func (l *FsrecordLogic) paserCallTime(callTimes types.CallTimes) *types.CallTimes {
	var calltime types.CallTimes = types.CallTimes{}
	loc, _ := time.LoadLocation("Asia/Shanghai")
	createdTime, _ := strconv.ParseInt(callTimes.CreatedTime, 10, 64)
	calltime.CreatedTime = time.UnixMicro(createdTime).In(loc).Format(time.DateTime)
	if callTimes.ProfileCreatedTime != "0" {
		profileCreatedTime, _ := strconv.ParseInt(callTimes.ProfileCreatedTime, 10, 64)
		calltime.ProfileCreatedTime = time.UnixMicro(profileCreatedTime).In(loc).Format(time.DateTime)
	}

	if callTimes.ProgressTime != "0" {
		progressTime, _ := strconv.ParseInt(callTimes.ProgressTime, 10, 64)
		calltime.ProgressTime = time.UnixMicro(progressTime).In(loc).Format(time.DateTime)
	}

	if callTimes.ProgressMediaTime != "0" {
		progressMediaTime, _ := strconv.ParseInt(callTimes.ProgressMediaTime, 10, 64)
		calltime.ProgressMediaTime = time.UnixMicro(progressMediaTime).In(loc).Format(time.DateTime)
	}

	if callTimes.AnsweredTime != "0" {
		answeredTime, _ := strconv.ParseInt(callTimes.AnsweredTime, 10, 64)
		calltime.AnsweredTime = time.UnixMicro(answeredTime).In(loc).Format(time.DateTime)
	}

	if callTimes.BridgedTime != "0" {
		bridgedTime, _ := strconv.ParseInt(callTimes.BridgedTime, 10, 64)
		calltime.BridgedTime = time.UnixMicro(bridgedTime).In(loc).Format(time.DateTime)
	}

	if callTimes.LastHoldTime != "0" {
		lastHoldTime, _ := strconv.ParseInt(callTimes.LastHoldTime, 10, 64)
		calltime.LastHoldTime = time.UnixMicro(lastHoldTime).In(loc).Format(time.DateTime)
	}

	if callTimes.HoldAccumTime != "0" {
		holdAccumTime, _ := strconv.ParseInt(callTimes.HoldAccumTime, 10, 64)
		calltime.HoldAccumTime = time.UnixMicro(holdAccumTime).In(loc).Format(time.DateTime)
	}

	if callTimes.HangupTime != "0" {
		hangupTime, _ := strconv.ParseInt(callTimes.HangupTime, 10, 64)
		calltime.HangupTime = time.UnixMicro(hangupTime).In(loc).Format(time.DateTime)
	}

	if callTimes.ResurrectTime != "0" {
		resurrectTime, _ := strconv.ParseInt(callTimes.ResurrectTime, 10, 64)
		calltime.ResurrectTime = time.UnixMicro(resurrectTime).In(loc).Format(time.DateTime)
	}

	if callTimes.TransferTime != "0" {
		transferTime, _ := strconv.ParseInt(callTimes.TransferTime, 10, 64)
		calltime.TransferTime = time.UnixMicro(transferTime).In(loc).Format(time.DateTime)
	}

	return &calltime
}

// 上传录音到阿里云OSS
func (l *FsrecordLogic) uploadRecordToOss(config config.Config, name string) error {
	var timeDir = time.Now().Local().Format("200601")
	var recordPath = fmt.Sprintf("%s%s/%s", config.OssAdmin.UploadDir, timeDir, name)

	cfg := oss.NewConfig()
	cfg.Region = &config.OssAdmin.Region
	cfg.Endpoint = &config.OssAdmin.EndPoint
	cfg.CredentialsProvider = credentials.NewStaticCredentialsProvider(config.OssAdmin.AccessKey, config.OssAdmin.Secret)

	// 创建OSS客户端
	client := oss.NewClient(cfg)

	putRequest := &oss.PutObjectRequest{
		Bucket:       oss.Ptr(config.OssAdmin.BucketName), // 存储空间名称
		Key:          oss.Ptr(recordPath),                 // 对象名称
		StorageClass: oss.StorageClassStandard,            // 指定对象的存储类型为标准存储
		Acl:          oss.ObjectACLPublicRead,             // 指定对象的访问权限为私有访问
	}

	// 执行上传对象的请求
	var localFile = fmt.Sprintf("%s/%s", config.FsUploadConf.RecordPath, name)
	result, err := client.PutObjectFromFile(context.TODO(), putRequest, localFile)
	if err != nil {
		logx.Infof("阿里云oss获取Bucket失败:%s", err.Error())
		return nil
	}

	logx.Infof("put object from file result:%#v\n", result.Status)

	//删除文件
	if err = os.Remove(localFile); err != nil {
		logx.Infof("阿里云oss上传成功，删除文件失败，失败原因:%s", err.Error())
		return nil
	}

	return nil
}

func NewFsrecordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FsrecordLogic {
	return &FsrecordLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}
